[AWS Amplify] ブラウザからMQTTで(AWS IoT Coreのメッセージブローカーに対して)Publish/Subscribeする
1 はじめに
IoT 事業部の平内(SIN)です。
AWS Amplify(以下、Amplify)で提供されるJavaScriptライブラリ(PubSubカテゴリ)を使用すると、ブラウザからAWS IoT CoreのメッセージブローカーへのPublish/Subscribeが、簡単に実装できます。
https://docs.amplify.aws/lib/pubsub/getting-started/q/platform/js/
上記のドキュメントでは、Cognitoで認証した状態での利用方法が説明されていますが、個人的に、ちょっと理解が難しかったので、今回、未認証での利用から、認証済み利用への移行という形で、実装方法を確認してみました。(既に、有用なコンテンツがある中、本記事が、個人的な備忘録となっていることをお許しください)
下記は、最終的に認証済みのブラウザと、AWS IoTコンソールのテスト画面でPublish及び、Subscribeの動作を確認している様子です。
2 Authカテゴリの追加
サンプルに使用したプラットフォームは、Vue 3です。
% vue create pub_sub_sample >Default (Vue 3) ([Vue 3] babel, eslint) % cd pub_sub_sample % amplify init
PubSubのライブラリを使用するためには、AWS IoTへのアクセス権付与のため、Authの追加が必須です。
Amplify CLIによる手順は以下の通りとなります。
% amplify add auth > Default configuration > Username % amplify push % amplify status Current Environment: dev ┌──────────┬──────────────────────┬───────────┬───────────────────┐ │ Category │ Resource name │ Operation │ Provider plugin │ ├──────────┼──────────────────────┼───────────┼───────────────────┤ │ Auth │ pubsubsampleaf4356ed │ No Change │ awscloudformation │ └──────────┴──────────────────────┴───────────┴───────────────────┘
また、ここでUIコンポーネントのインストールと、リソース情報の受け渡し設定を完了させておきます。
% yarn add aws-amplify @aws-amplify/ui-components
src/main.js
import { createApp } from 'vue' import App from './App.vue' // 追加 import Amplify from 'aws-amplify'; import aws_exports from './aws-exports'; import { applyPolyfills, defineCustomElements, } from '@aws-amplify/ui-components/loader'; Amplify.configure(aws_exports); applyPolyfills().then(() => { defineCustomElements(window); }); createApp(App).mount('#app')
3 未認証での利用
(1) ポリシー作成
最初に、my_client_idで接続し、my_topicにPubulish/Subscribeする事ができるポリシーを作成します。
pub_sub_sample_policy
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": [ "arn:aws:iot:ap-northeast-1:*:client/my_client_id" ] }, { "Effect": "Allow", "Action": [ "iot:Publish", "iot:Receive" ], "Resource": [ "arn:aws:iot:ap-northeast-1:*:topic/my_topic" ] }, { "Effect": "Allow", "Action": [ "iot:Subscribe" ], "Resource": [ "arn:aws:iot:ap-northeast-1:*:topicfilter/my_topic" ] } ] }
(2) 未認証アクセスの有効化
Anplifyのコンソールから、セットアップされたCognitoのコンソールを開き、プールIDの編集から、 「認証されていない ID に対してアクセスを有効にする」 にチェックを入れます。
(3) Role(未認証)へのポリシー追加
続いて、未認証で使用されるロールに、先ぽどのポリシー(pub_sub_sample_policy)を追加します。
(4) 動作確認
App.vueを以下のように編集し、PubSub.publish() 及び、PubSub.subscribe() を実装します。
App.vue
<template> <h1>Pub/Sub</h1> <input type="text" v-model="message" placeholder="メッセージ"> <button v-on:click="publish">Publish</button> <div v-for="item in items" :key="item.message"> <p>{{ item.message }}</p> </div> </template> <script> import Amplify,{ PubSub } from 'aws-amplify'; import { AWSIoTProvider } from '@aws-amplify/pubsub'; const AWS_REGION = 'ap-northeast-1'; const ENDPOINT = 'xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com'; const TOPIC = 'my_topic'; Amplify.addPluggable(new AWSIoTProvider({ aws_pubsub_region: AWS_REGION, aws_pubsub_endpoint: `wss://${ENDPOINT}/mqtt`, clientId: 'my_client_id' })); export default { name: 'App', async created() { this.subscribe() }, data() { return { items: [] } }, methods: { async subscribe() { PubSub.subscribe(TOPIC).subscribe({ next: data => { console.log(data.value.message) this.items = [...this.items, {'message': data.value.message}]; }, error: error => console.error(error), close: () => console.log('Done'), }); }, async publish() { const { message } = this; if (!message) return; await PubSub.publish(TOPIC, { message: message }); this.message = ''; } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } input{ width: 300px; height:30px; } button { margin:10px; width: 70px; height: 38px; border: solid 1px silver; border-radius: 0.5rem 0.5rem; } button:active{ padding-top:6px; padding-bottom:4px; border:1px solid #334c66; background-color:#69c; color:#ffffff; } </style>
Iot Core コンソールのテストクライアントで、メッセージのやり取りを確認できます。ここで分かる通り、未認証で利用する場合、当該ロールに権限を付与するだけで利用できることになります。
(5) 未認証の無効化
未認証でのPublish及び、Subscribeが確認できましたが、続いて、認証時の動作を確認するために、いったん、未認証によるアクセスを無効化します。
無効化した時点で、Subscribe、Publishは、共にエラーとなって接続できなくなる事が確認できます。
4 認証有りでの利用
(1) 認証画面
認証を有効にするために、App.vueのtemplateに、Amplify Framework UIコンポーネント( <amplify-authenticator> 及び、<amplify-sign-out> )を追加します。
src/App.vue
<template> <amplify-authenticator> <amplify-sign-out></amplify-sign-out> <h1>Pub/Sub</h1> <input type="text" v-model="message" placeholder="メッセージ"> <button v-on:click="publish">Publish</button> <div v-for="item in items" :key="item.message"> <p>{{ item.message }}</p> </div> </amplify-authenticator> </template>
追加すると、認証されていない場合の画面は、下記のようになります。
Create accountでアカウントを作成し、ログインした状態(認証済み)になると、下記のような画面となります。
(2) Role(認証済み)へのポリシー追加
認証済みの際に有効となるロールに、AWSIoTDataAccess 及び、AWSIoTConfigAccess を追加します。
ここでは、詳細なアクセス制御が行われていませんが、この後で設定する個々のアカウントに対するポリシーで設定することが可能です。
(3) ポリシー作成
今回作成するポリシーは、IoT Coreのポシリーです。内容は、先にIAMで作成したものと同じとなっています。 (名前は、pub_sub_sample_policyとしました)
(4) IDENTITY_IDへのポリシー追加
上記で作成したポリシーは、IDENTITY_IDに紐付けます。
この作業は、コンソールからは行えないため、AWS CLIからの作業になります。
% aws iot attach-policy --policy-name pub_sub_sample_policy --target '<YOUR_COGNITO_IDENTITY_ID>'
なお、IDENTITY_IDは、CognitoのコンソールのIDブラウザで確認できます。現在、1つのアカウントを作成してログインしたので、1つだけ表示されている事が確認できます。
紐付けが完了すると、ポリシーの「証明書」一覧に、表示されます。
(5) 動作確認
ここまでの作業が完了すると、ログインすることで、Pub/Subがエラーなく動作することを確認できます。
5 最後に
今回は、Amplifyによる、PubSubライブラリの利用について確認してみました。個人的には、アカウント単位のIDENTITY_IDにポリシーを紐づけるあたりの作業が、ちょっと理解に苦労しました。